/*
 *
 * Copyright (c) 2007, Sun Microsystems, Inc.
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *  * Neither the name of Sun Microsystems nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package ace.system.sound;

/**
 *
 * @author TimotiusNC
 */

import javax.microedition.media.*;
import javax.microedition.media.control.*;

/**
 * An example MIDlet to demonstrate simple tones: Manager.playTone(), MIDIControl
 *
 * @version 1.3
 */
public class SimpleTones {
	public static final int C4 = ToneControl.C4;
	public static final int DRUM_C_HI_HAT	= 1;
	public static final int DRUM_O_HI_HAT	= 2;
	public static final int DRUM_TAMBOURINE	= 3;
	public static final int DRUM_HI_TOM		= 4;
	public static final int DRUM_MID_TOM	= 5;
	public static final int DRUM_LO_TOM		= 6;
	public static final int DRUM_R_CYMBAL	= 7;
	public static final int DRUM_COW_BELL	= 8;
	public static final int DRUM_C_CYMBAL	= 9;
	public static final int DRUM_BASS		= 10;
	public static final int DRUM_H_CLAP		= 11;
	public static final int DRUM_SNARE		= 12;
	public static final int MIDI_SHORT		= 13;
	public static final int MIDI_LONG		= 14;

    public SimpleTones() {
		isMute	= false;
    }

    public void destroyTones(boolean unconditional) {
		if(mc != null){
			mc = null;
		}
		
		if (mp != null) {
			mp.close();
			mp = null;
		}
    }

	public void setMute(boolean mute){
		isMute = mute;
	}    

	//PLAYING TONES
    public void simpleTone(int note, int duration) {
		if(isMute) return;
		try {
			//playNote(ToneControl.C4 + 4, 1000, 100);
			Manager.playTone(note, duration, 100);
		} catch (Exception ex){}
    }

	public void definedSimpleTone(int tone){
		switch(tone){
			case MIDI_SHORT:
				midiShort();
				break;
			case MIDI_LONG:
				midiLong();
				break;
			default:
				midiDrum(tone);
				break;
		}
	}

	private void midiDrum(int num){
		if(isMute) return;
		try{
			if(mc == null)
				mc = getMIDIControl();

			mc.shortMidiEvent(0x99, DRUM_NUMBERS[num], 120);
			mc.shortMidiEvent(0x99, DRUM_NUMBERS[num], 0);
		} catch (Exception ex){}
	}

    private void midiShort() {
		if(isMute) return;
		try {
			if(mc == null)
				mc = getMIDIControl();

			// some notes on channel 0
			// 0x90: Note On
			for (int i=0; i<niceChord.length; i++) {
				mc.shortMidiEvent(0x90, niceChord[i], 127); // Note On, note number, velocity
			}
			
			// some drums on channel 9
			mc.shortMidiEvent(0x99, 35, 127); // bass drum
			mc.shortMidiEvent(0x99, 35, 0);
			mc.shortMidiEvent(0x99, 58, 127); // vibraslap
			mc.shortMidiEvent(0x99, 58, 0);
			mc.shortMidiEvent(0x99, 57, 127); // crash cymbal
			mc.shortMidiEvent(0x99, 57, 0);
			Thread.sleep(200);

			// turn off all notes: Note On event with 0 velocity
			for (int i=0; i<niceChord.length; i++) {
				mc.shortMidiEvent(0x90, niceChord[i], 0);
			}
		} catch (Exception ex){}
    }

    private void midiLong() {
		if(isMute) return;
		try {
			if(mc == null)
				mc = getMIDIControl();

			// send the chord as sys ex event
			int len=niceChord.length*3; // 3 bytes per event
			byte[] data=new byte[len];
			int c=0;

			for (int i=0; i<len/3; i++) {
				data[c++]=(byte) 0x90;
				data[c++]=niceChord[i % niceChord.length];
				data[c++]=127;
			}
			Thread.sleep(200);

			// replace the velocity by 0
			for (int i=2; i<len; i+=3) {
				data[i]=0;
			}
		} catch (Exception ex){}
    }

	private MIDIControl getMIDIControl() throws Exception {
		if (mp == null) {
			mp = Manager.createPlayer(Manager.MIDI_DEVICE_LOCATOR);
			mp.prefetch();
		}

		if (mc == null)	mc = (MIDIControl) mp.getControl("javax.microedition.media.control.MIDIControl");

		return mc;
    }

	//ATTRIBUTES
    private Player		mp; // cache MIDIPlayer so that we don't open/close all the time
	private MIDIControl mc; // cache MIDIControl so that we don't open/close all the time
	private boolean	isMute;

	private byte[] niceChord=new byte[] {
		0x2B, 0x40, 0x44, 0x4C, 0x53, 0x58, 0x23, 0x3B, 0x32, 0x1F
    };

	private static final int[] DRUM_NUMBERS = {
    	0,    // not used
    	0x2A, // 1: closed hihat
    	0x2E, // 2: open hihat
    	0x36, // 3: Tambourine
    	0x32, // 4: hi tom
    	0x2F, // 5: mid tom
    	0x2B, // 6: low tom
		0x33, // 7: ride cymbal
		0x38, // 8: cow bell
		0x31, // 9: crash cymbal
    	0x24, // *: bass drum
    	0x27, // 0: hand clap
    	0x28, // #: snare drum
    };
}
